package com.atguigu.security.filter;

import com.alibaba.fastjson.JSON;
import com.atguigu.common.jwt.JwtHelper;
import com.atguigu.common.result.ResponseUtil;
import com.atguigu.common.result.Result;
import com.atguigu.common.result.ResultCodeEnum;
import com.atguigu.security.custom.CustomUser;
import com.atguigu.vo.system.LoginVo;
import com.fasterxml.jackson.databind.ObjectMapper;
import lombok.extern.slf4j.Slf4j;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
import org.springframework.security.web.util.matcher.AntPathRequestMatcher;

import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;

/**
 * @author 13353
 */
@Slf4j
public class TokenLoginFilter extends UsernamePasswordAuthenticationFilter {

    //引入redis用户存放用户的按钮权限
    private RedisTemplate redisTemplate;

    /**
     * 构造方法
     */
    public TokenLoginFilter(AuthenticationManager authenticationManager,
                            RedisTemplate redisTemplate){
        this.setAuthenticationManager(authenticationManager);
        //指定登录接口及提交方式，可以指定任意路径
        this.setPostOnly(false);
        // 登录路径和提交方式
        this.setRequiresAuthenticationRequestMatcher(new AntPathRequestMatcher("/admin/system/index/login","POST"));
        this.redisTemplate = redisTemplate;
    }

    //登录认证
    //获取输入的用户名和密码，嗲用方法认证。
    @Override
    public Authentication attemptAuthentication(HttpServletRequest request
            , HttpServletResponse response)
            throws AuthenticationException{
        try {
            //获取用户信息
            //readValue,输入流转换为一个 LoginVo 对象。
            LoginVo loginVo = new ObjectMapper().readValue(request.getInputStream(), LoginVo.class);
            log.info("=======loginvo===={},{}",loginVo.getPassword(),loginVo.getUsername());
            //封装对象
            Authentication authenticationToken =
                    new UsernamePasswordAuthenticationToken(loginVo.getUsername(),loginVo.getPassword());

            //调用方法，完成认证
            return this.getAuthenticationManager().authenticate(authenticationToken);
        } catch (IOException e) {
            throw new RuntimeException(e);
        }

    }

    //认证成功调用方法
    @Override
    protected void successfulAuthentication(HttpServletRequest request,
                                            HttpServletResponse response,
                                            FilterChain chain,
                                            Authentication auth)
            throws IOException, ServletException {
        //获取当前用户
        CustomUser customUser = (CustomUser) auth.getPrincipal();

        //生成token
        String token = JwtHelper.createToken(customUser.getSysUser().getId(), customUser.getSysUser().getUsername());

        //获取当前用户权限数据，放到Redis里面，key:username  value: 权限数据
        redisTemplate.opsForValue().set(customUser.getUsername(), JSON.toJSONString(customUser.getAuthorities()));
        //返回
        Map<String,Object> map = new HashMap<>();
        map.put("token",token);
        //不是在controller中，需要使用返回的工具类，进行处理。
        ResponseUtil.out(response, Result.ok(map));

    }

    //认证失败调用的方法
    @Override
    protected void unsuccessfulAuthentication(HttpServletRequest request,
                                              HttpServletResponse response,
                                              AuthenticationException failed) throws IOException, ServletException {
        //返回认证失败。
        ResponseUtil.out(response,Result.build(null, ResultCodeEnum.LOGIN_ERROR));

    }

}
